#ifndef _NE_RESOURCE_MANAGER_H_
#define _NE_RESOURCE_MANAGER_H_

#include <system/Resource.h>

namespace ne
{
    typedef std::pair<ResourcePtr, bool> ResourceCreateOrRetrieveResult;

    class NEAPI ResourceManager : public ManualResourceLoader
    {
        public:
            ResourceManager();

            virtual ResourcePtr create(const std::string &name,
                                       const std::string &fileName="",
                                       const bool isManual=false,
                                       ManualResourceLoader *pLoader=0);

            virtual ResourceCreateOrRetrieveResult createOrRetrieve(const std::string &name,
                                                                    const std::string &fileName="",
                                                                    const bool isManual=false,
                                                                    ManualResourceLoader *pLoader=0);

            virtual ResourcePtr prepare(const std::string &name,
                                        const std::string &fileName,
                                        const bool isManual=false,
                                        ManualResourceLoader *pLoader=0,
                                        const bool backgroundThread=false);

            virtual ResourcePtr load(const std::string &name,
                                     const std::string &fileName,
                                     const bool isManual=false,
                                     ManualResourceLoader *pLoader=0,
                                     const bool backgroundThread=false);

            virtual bool unloadByID(const uint64_t id);
            virtual bool unloadByName(const std::string &name);
            virtual void unloadUnreference(const bool reloadableOnly=true);
            virtual void unloadAll(const bool reloadableOnly=true);

            virtual bool reloadByID(const uint64_t id);
            virtual bool reloadByName(const std::string &name);
            virtual void reloadUnreference(const bool reloadableOnly=true);
            virtual void reloadAll(const bool reloadableOnly=true);

            virtual bool downloadByID(const uint64_t id);
            virtual bool downloadByName(const std::string &name);
            virtual void downloadUnreference();
            virtual void downloadAll();

            virtual bool hasID(const uint64_t id) const;
            virtual bool hasName(const std::string &name) const;

            virtual ResourcePtr getByID(const uint64_t id) const;
            virtual ResourcePtr getByName(const std::string &name) const;

            virtual bool removeByPtr(const ResourcePtr &pResource);
            virtual bool removeByID(const uint64_t id);
            virtual bool removeByName(const std::string &name);
            virtual void removeUnreference(const bool reloadableOnly=true);
            virtual void removeAll();

            virtual void setMemoryBudget(const size_t budget)
            {
                mMemoryBudget = budget;
                checkMemoryUsage();
            }

            virtual size_t getMemoryBudget() const
            {
                return mMemoryBudget;
            }

            virtual size_t getMemoryUsage() const
            {
                return mMemoryUsage;
            }

            virtual size_t getResourceCount() const
            {
                return mResourceMap.size();
            }

            virtual const ResourceMap& getResourceMap() const
            {
                return mResourceMap;
            }

            virtual const ResourceIDMap& getResourceIDMap() const
            {
                return mResourceIDMap;
            }

            // ManualResourceLoader
            virtual bool prepareResource(Resource* resource)
            {
                (void)resource;
                return true;
            }

            virtual bool loadResource(Resource* resource)
            {
                (void)resource;
                return true;
            }

            // Resource::Listener
            virtual void onPreparingComplete(Resource *pResource) {}
            virtual void onLoadingComplete(Resource *pResource);
            virtual void onUnloadingComplete(Resource *pResource);
            virtual void onDownloadingComplete(Resource *pResource) {}

            const std::string& getResourceType() const
            {
                return mResourceType;
            }

            virtual ~ResourceManager();

        protected:
            uint64_t getNextID();

            virtual Resource* createImplement(const uint64_t id,
                                              const std::string &name,
                                              const std::string &fileName,
                                              const bool isManual,
                                              ManualResourceLoader *pLoader) = 0;

            virtual bool addImplement(const ResourcePtr &pResource);

            virtual bool removeImplement(const ResourcePtr &pResource);

            virtual void checkMemoryUsage();

        public:
            static uint32_t RESOURCE_INTERNAL_REFERENCE;

        protected:
            Mutex mMutex;
            ResourceMap mResourceMap;
            ResourceIDMap mResourceIDMap;
            uint64_t mNextID;
            size_t mMemoryBudget;
            size_t mMemoryUsage;

            //TODO: mResourceType need a string value
            std::string mResourceType;
    };
}

#endif

